package com.free.semantic.req;

import com.free.semantic.common.RangeObj;
import com.free.semantic.common.RelationItem;
import com.free.semantic.core.ConceptManage;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;

public class RelaItemDef {


    private String name;

    private List<RangeObj> sourceObjectList;

    private RangeObj destObject;

    private int count;

    public RelationItem buildInstance(Map<String, String> variableMap, ConceptManage conceptManage) {
        RelationItem item = new RelationItem();
        item.setName(name);
        List<RangeObj> source = new ArrayList<>();
        RangeObj dest = destObject.withOtherName(calculateObjName(destObject.getObjectName(), variableMap, conceptManage));
        for (RangeObj rangeObj : sourceObjectList) {
            source.add(rangeObj.withOtherName(calculateObjName(rangeObj.getObjectName(), variableMap, conceptManage)));
        }
        item.setSourceObjectList(source);
        item.setDestObject(dest);
        return item;
    }

    // A.B 代表 A是事物，B是关系
    // A->B 代表 A是事物，B 也是事物，计算的结果是一个关系
    private String calculateObjName(String formula, Map<String, String> variableMap, ConceptManage conceptManage) {
        if (formula.contains(".")) {
            String[] split = formula.split("\\.");
            if (split.length != 2) {
                throw new IllegalArgumentException(String.format("表达式：%s语法错误", formula));
            }
            String sourceObj = variableMap.get(split[0]);
            sourceObj = calculateRawObj(sourceObj, conceptManage);
            List<String> allConnectByRelation =
                    conceptManage.findAllConnectByRelation(Lists.newArrayList(sourceObj), split[1]);
            if (CollectionUtils.isEmpty(allConnectByRelation)) {
                throw new IllegalArgumentException(String.format("表达式：%s不存在,source:%s", formula, sourceObj));
            }
            if (allConnectByRelation.size() > 1) {
                throw new IllegalArgumentException(String.format("表达式：%s超过一个", formula));
            }
            return allConnectByRelation.get(0);
        } else {
            return calculateRawObj(variableMap.getOrDefault(formula, formula), conceptManage);
        }
    }

    private String calculateRawObj(String formula, ConceptManage conceptManage) {
        if (formula.contains(".")) {
            String[] split = formula.split("\\.");
            if (split.length != 2) {
                throw new IllegalArgumentException(String.format("表达式：%s语法错误", formula));
            }
            List<String> allConnectByRelation =
                    conceptManage.findAllConnectByRelation(Lists.newArrayList(split[0]), split[1]);
            if (CollectionUtils.isEmpty(allConnectByRelation)) {
                throw new IllegalArgumentException(String.format("表达式：%s不存在", formula));
            }
            if (allConnectByRelation.size() > 1) {
                throw new IllegalArgumentException(String.format("表达式：%s超过一个", formula));
            }
            return allConnectByRelation.get(0);

        } else {
            return formula;
        }
    }

    public RelaItemDef(List<RangeObj> sourceObjectList, RangeObj destObject) {
        if (CollectionUtils.isEmpty(sourceObjectList) || destObject == null) {
            throw new IllegalArgumentException("来源或目的事物为空");
        }
        count = sourceObjectList.size() + 1;
        Set<String> allVari = new HashSet<>();
        for (RangeObj rangeObj : sourceObjectList) {
            allVari.add(rangeObj.getObjectName());
        }
        allVari.add(destObject.getObjectName());
        if (count != allVari.size()) {
            throw new IllegalArgumentException("关系变量异常");
        }
        this.sourceObjectList = sourceObjectList;
        this.destObject = destObject;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<RangeObj> getSourceObjectList() {
        return sourceObjectList;
    }

    public void setSourceObjectList(List<RangeObj> sourceObjectList) {
        this.sourceObjectList = sourceObjectList;
    }

    public RangeObj getDestObject() {
        return destObject;
    }

    public void setDestObject(RangeObj destObject) {
        this.destObject = destObject;
    }

}
